//
//  WCILocalAuthentication.m
//  MOPrefix
//
//  Created by Hyukooooh on 2024/4/2.
//

#import "WCILocalAuthentication.h"
#import <LocalAuthentication/LocalAuthentication.h>
#import "MPLockHelper.h"
@implementation WCILocalAuthentication

//判断设备支持的类型， 因为如果设备未设置faceID或touchID，biometryType会返回LABiometryTypeNone,不符合某些需求场景，所以通过设备类型判断
+ (MOLocalAuthenticationType)deviceSupportAuthType{
    BOOL isIPhoneXSeries = [WCILocalAuthentication isIPhoneXSeries];
    return isIPhoneXSeries ? MOLocalAuthenticationType_faceID : MOLocalAuthenticationType_touchID;
}

//判断生物识别的状态
+ (void)judgeBiometricsStatusComplete:(void(^)(BOOL availabel))complete{
    LAContext *context = [[LAContext alloc] init];
    // 检查设备是否支持 Touch ID
    NSError *error = nil;
    BOOL can = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
    if(can){
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Biometrics状态 可用");
            !complete?:complete(YES);
        });
    }else{
        switch (error.code) {
            
            case LAErrorBiometryNotAvailable:
            {
                //用户禁止使用生物识别功能
                [self OpenPermissions:NO];
                break;
            }
            case LAErrorBiometryNotEnrolled:
            {
                //用户禁止授权
                NSLog(@"Biometrics状态 设备Touch ID不可用，用户未录入");
                break;
            }
            default:
                break;
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Biometrics状态 不可用 %ld",error.code);
            !complete?:complete(NO);
        });
    }
}

+ (void)localAuth:(MOLocalAuthenticationType)type isUnlock:(BOOL)isUnlock result:(void(^)(BOOL success, BOOL isAuthFail))result{
    //创建LAContext
    LAContext *context = [LAContext new];
    //这个属性是设置指纹输入失败之后的弹出框的选项 如果不填默认会有一个"输入密码按钮"
//    context.localizedFallbackTitle = @"";如果不设置空值，则AlertView弹窗默认会有“输入密码”的选项，但是在LAPolicyDeviceOwnerAuthenticationWithBiometrics模式下点击“输入密码”不会有反应；LAPolicyDeviceOwnerAuthentication模式下点击可以唤起输入手机密码页面，页面如下，其中除了“指纹”两字是你的app名称，其他都不可定制
    context.localizedFallbackTitle = @"";
    
    NSLog(@"支持指纹识别");
    //这个是用来验证TouchID的，会有弹出框出来

    [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"需要进行身份识别认证" reply:^(BOOL success, NSError * _Nullable error) {
        if (success) {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"Touch ID 验证成功");
                !result?:result(YES,NO);
            });
        }else{
            NSLog(@"Touch ID总 %@",error.localizedDescription);
            //解锁用 不同于开启，只有真正的识别错误才能判定为false。 如LAErrorUserCancel用户取消等（识别失败过后才会有取消按钮）
            BOOL isAuthFail = NO;
            switch (error.code) {
                case LAErrorSystemCancel:
                {
                    //失败弹窗弹出时，用户切换app
                    NSLog(@"Touch ID 系统取消授权，如其他APP切入");
                    isAuthFail = YES;
                    break;
                }
                case LAErrorUserCancel:
                {
                    //失败弹窗弹出时，用户点击取消
                    NSLog(@"Touch ID 用户取消验证Touch ID");
                    isAuthFail = YES;
                    break;
                }
                case LAErrorAuthenticationFailed:
                {
                    //指纹识别3次失败进入这里
                    NSLog(@"Touch ID 授权失败");
                    isAuthFail = YES;
                    break;
                }
                case LAErrorUserFallback:
                {
                    //失败弹窗点击输入密码按钮
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        NSLog(@"Touch ID 用户选择输入密码，切换主线程处理");
                    }];
                    isAuthFail = YES;
                    break;
                }
                case LAErrorBiometryLockout:
                {
                    //失败次数过多，被系统禁用
                    NSLog(@"Touch ID 在使用touchID的场景中,错误太多次（根据策略不同为5次到6次）而导致touchID被锁不可用");
                    [self lockoutNotice];
                }
                    break;
                case LAErrorBiometryNotAvailable:
                {
                    //用户禁止授权
                    NSLog(@"Touch ID 设备Touch ID不可用，例如未打开");
                    [self OpenPermissions:YES];
                    break;
                }
                case LAErrorBiometryNotEnrolled:
                {
                    //设备未设置面容解锁
                    NSLog(@"Touch ID 设备Touch ID不可用，用户未录入");
                    if(!isUnlock){
                        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                            [MOAlerter alertWithMessage:@"您尚未设置面容ID,请先在手机系统\"设置\"中录入面容" confirmTitle:@"确定"];
                        }];
                    }
                    break;
                }
                case LAErrorPasscodeNotSet:
                {
                    //可以忽略的类型 基本不会出现
                    NSLog(@"Touch ID 系统未设置密码");
                    break;
                }
                default:
                {
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        NSLog(@"Touch ID 其他情况，切换主线程处理");
                    }];
                    break;
                }
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                !result?:result(NO,isAuthFail);
            });
        }
    }];
}

+ (void)OpenPermissions:(BOOL)shouldOpen{
    dispatch_async(dispatch_get_main_queue(), ^{
        MOLocalAuthenticationType supportType = [WCILocalAuthentication deviceSupportAuthType];
        NSString *str = supportType == MOLocalAuthenticationType_faceID ? @"面容ID" : @"指纹ID";
        [MOAlerter alertWithTitle:@"" message:[NSString stringWithFormat:(@"应用无%@权限，请先在手机系统\"设置-吉信\"中开启权限"),str] leftTitle:shouldOpen?@"取消":@"" leftAction:^(MOAlerter *alerter) {
            
        } rightTitle:shouldOpen?@"去开启":@"好的" rightAction:^(MOAlerter *alerter) {
            if(shouldOpen){
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success) {
                    
                }];
            }
            
        } touchHide:NO];
    });
}

+ (void)lockoutNotice{
    MOLocalAuthenticationType supportType = [WCILocalAuthentication deviceSupportAuthType];
    NSString *str = supportType == MOLocalAuthenticationType_faceID ? @"面容ID" : @"指纹ID";
    NSString *title = [NSString stringWithFormat:(@"超出%@尝试次数"),str];
    NSString *desc = [NSString stringWithFormat:(@"无法使用%@"),str];
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        //错误次数过多，面容识别功能被系统锁定
        [MOAlerter alertWithTitle:title message:desc leftTitle:@"" leftAction:^(MOAlerter *alerter) {
            
        } rightTitle:@"好的" rightAction:^(MOAlerter *alerter) {
           
        } touchHide:NO];
    }];
}

+ (void)evaluatedPolicyDomainStateChangedComplete:(void(^)(BOOL changed,BOOL shouldAlert))complete{
    LAContext *context = [[LAContext alloc] init];
    NSError *error = nil;
    BOOL can = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
    if (!can) {
        // Face ID 不可用或发生错误
        dispatch_async(dispatch_get_main_queue(), ^{
            !complete?:complete(NO,error.code == LAErrorBiometryNotEnrolled);
        });
        return;
    }
    
    NSData *currentDomainState = context.evaluatedPolicyDomainState;
    NSData *savedDomainState = [self getSavedDomainState]; // 获取先前保存的状态数据
    if (savedDomainState != nil && currentDomainState != nil) {
        // 比较当前状态数据和保存的状态数据
        dispatch_async(dispatch_get_main_queue(), ^{
            BOOL changed = ![savedDomainState isEqualToData:currentDomainState];
            !complete?:complete(changed,changed);
        });
        return;
    }
    
    // 保存当前状态数据
    [self saveDomainState:currentDomainState];
    dispatch_async(dispatch_get_main_queue(), ^{
        !complete?:complete(NO,NO);
    });
}


+ (void)saveCurrentDomainState{
    LAContext *context = [[LAContext alloc] init];
    NSError *error = nil;
    
    if (![context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
        // Face ID 不可用或发生错误
        return;
    }
    
    NSData *currentDomainState = context.evaluatedPolicyDomainState;
    if (currentDomainState == nil) {
        return;
    }
    // 保存当前状态数据
    [self saveDomainState:currentDomainState];
}

+ (NSData *)getSavedDomainState {
    // 从存储中获取先前保存的状态数据
    // 返回一个 NSData 对象，或者返回 nil（如果没有保存的数据）
//    return WCICache.policyDomainState;
    return nil;
}

+ (void)saveDomainState:(NSData *)domainState {
    // 将当前状态数据保存到存储中
//    WCICache.policyDomainState = domainState;
}

+ (NSString *)domainStateChangedNotice{
    MOLocalAuthenticationType supportType = [WCILocalAuthentication deviceSupportAuthType];
    NSString *str = supportType == MOLocalAuthenticationType_faceID ? @"面容ID" : @"指纹ID";
    return [NSString stringWithFormat:(@"您设备中%@发生了变化，为了保护您的账户安全，请使用其他方式解锁后重新开启"),str];
}

+ (NSString *)vipExpiredNotice{
    return [NSString stringWithFormat:(@"您的VIP会员已过期，%@%@特权已失效，功能已关闭"),[self authenticationTypeName],[MPLockHelper getUnregisterCount] > 0 ? (@"、解锁错误自动注销"):@""];
}

+ (NSString *)authenticationTypeName{
    MOLocalAuthenticationType supportType = [WCILocalAuthentication deviceSupportAuthType];
    return supportType == MOLocalAuthenticationType_faceID ? @"面容ID解锁" : @"指纹ID解锁";
}

+ (BOOL)isIPhoneXSeries{
    BOOL iPhoneXSeries = NO;
    if (UIDevice.currentDevice.userInterfaceIdiom != UIUserInterfaceIdiomPhone) {
        return iPhoneXSeries;
    }
    
    if (@available(iOS 11.0, *)) {
        UIWindow *mainWindow = [WCILocalAuthentication getKeyWindow];
        if (mainWindow.safeAreaInsets.bottom > 0.0) {
            iPhoneXSeries = YES;
        }
    }
    
    return iPhoneXSeries;
}

+ (UIWindow *)getKeyWindow{
    UIWindow *keyWindow = nil;
    if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(window)]) {
        keyWindow = [[UIApplication sharedApplication].delegate window];
    }else{
        NSArray *windows = [UIApplication sharedApplication].windows;
        for (UIWindow *window in windows) {
            if (!window.hidden) {
                keyWindow = window;
                break;
            }
        }
    }
    return keyWindow;
}
@end
